// Copyright 2019 The rhyme_lph Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// s [author] rhyme_lph
// M [email]  rhymelph@gmail.com
// n [github] https://github.com/rhymelph

import 'dart:async';

import 'package:base_plugin/base_plugin.dart';
import 'package:finance_app/generated/l10n.dart';
import 'package:finance_app/src/entities/business_contact_entity.dart';
import 'package:finance_app/src/entities/credit_note_detail_entity.dart';
import 'package:finance_app/src/entities/credit_note_entity.dart';
import 'package:finance_app/src/entities/invoice_entity.dart';
import 'package:finance_app/src/entities/ocr_attachment_entity.dart';
import 'package:finance_app/src/http_service/http_credit_note_service.dart';
import 'package:finance_app/src/mixin/form_item_amount_mixin.dart';
import 'package:finance_app/src/mixin/from_attach_mixin.dart';
import 'package:finance_app/src/mixin/init_edit_data_mixin.dart';
import 'package:finance_app/src/page/dashboard/credit_note/new_credit_note_page.dart';
import 'package:finance_app/src/router_gen/router_gen_providers.dart';
import 'package:finance_app/src/utils/date_time_utils.dart';
import 'package:finance_app/src/widgets/bottom_sheet/calendar_bottom_sheet.dart';
import 'package:finance_app/src/widgets/bottom_sheet/delete_info_bottom_sheet.dart';
import 'package:finance_app/src/widgets/bottom_sheet/got_it_tip_bottom_sheet.dart';
import 'package:flutter/material.dart';

class NewCreditNoteProvider extends BaseProvider<CreditNoteDetailEntity>
    with InitEditDataMixin, FormItemAmountMixin, FormAttachMixin {
  BusinessContactEntity issueTo;

  InvoiceEntity invoiceNumber;

  TextEditingController creditNoteNumberController = TextEditingController();
  FocusNode creditNoteNumberFocusNode = FocusNode();

  TextEditingController notesController = TextEditingController();
  FocusNode notesFocusNode = FocusNode();

  List<String> menuList = [];

  @override
  int get billInvoiceId => invoiceNumber?.id;

  @override
  void initState() {
    isCredit = true;
    super.initState();
  }

  @override
  void dispose() {
    super.dispose();
    creditNoteNumberController.dispose();
    creditNoteNumberFocusNode.dispose();
    notesController.dispose();
    notesFocusNode.dispose();
  }

  bool isSelectMode = false;

  void onSelectMenu(String value) {
    switch (value) {
      case 'Edit':
        onChangeEditMode();
        break;
      case 'Delete':
        onDelete();
        break;
      case 'Make A Refund':
        onMakeARefund();
        break;
      case 'Keep As Credit':
        onKeepAsCredit();
        break;
      case 'See Payment':
        onSeePayment();
        break;
    }
  }

  void onSeePayment() async {
    await Routes.navigateTo(RouterGenProviders.seePaymentPage, params: {
      'creditId': data.id,
      'isClosed': true,
    });
    loadData();
  }

  void unFocus() {
    creditNoteNumberFocusNode.unfocus();
    notesFocusNode.unfocus();
  }

  void onSave() async {
    unFocus();
    if (creditNoteNumberController.text.length == 0) {
      showToast(S.current.please_enter_the_credit_note_number);
      return;
    }

    if (date == null) {
      showToast(S.current.please_select_issue_date);
      return;
    }

    if (issueTo == null) {
      showToast(S.current.please_select_issue_to);
      return;
    }

    if (invoiceNumber == null) {
      showToast(S.current.please_select_invoice_number);
      return;
    }

    if (serviceAndProductList.length == 0) {
      showToast(S.current.please_add_item);
      return;
    }

    CreditNoteEntity orderEntity;

    List<int> attachmentIds = await uploadFiles();
    if (attachmentIds == null) return;

    List item = serviceAndProductList
        .map((e) => {
              'type': e.product != null && e.product.id != null
                  ? 'product'
                  : 'service',
              'type_id': e.id,
              'name': e.name,
              'quantity': e.number,
              'price': e.price,
              'is_tax_inclusive': e.isInclusive ? 1 : 0,
              'tax_id': e.tax.id,
              'tax_amount': e.taxAmount,
              'discount_type': e.discountType,
              'discount_value': e.discountValue,
            })
        .toList();

    if (isEdit == true) {
      await post(
          HttpCreditNoteService.updateCreditNote(
            data?.id,
            contact_id: issueTo?.id,
            invoice_id: invoiceNumber?.id,
            number: creditNoteNumberController?.text,
            issued_at: DateTimeUtils.formatDateTime(date, 'yyyy-MM-dd'),
            subtotal: subTotal,
            tax_amount: gst,
            total: total,
            notes: notesController?.text,
            attachment_ids: attachmentIds,
            item: item,
          ),
          loadingTip: S.current.loading,
          autoHandler: AutoHandler.Toast, onSuccess: (result) {
        orderEntity = getEntityFromResult<CreditNoteEntity>(result);
      });
    } else {
      await post(
          HttpCreditNoteService.createCreditNote(
            contact_id: issueTo?.id,
            invoice_id: invoiceNumber?.id,
            number: creditNoteNumberController?.text,
            issued_at: DateTimeUtils.formatDateTime(date, 'yyyy-MM-dd'),
            subtotal: subTotal,
            tax_amount: gst,
            total: total,
            notes: notesController?.text,
            attachment_ids: attachmentIds,
            item: item,
          ),
          loadingTip: S.current.loading,
          autoHandler: AutoHandler.Toast, onSuccess: (result) {
        orderEntity = getEntityFromResult<CreditNoteEntity>(result);
      });
    }
    if (orderEntity != null) {
      if (isSelectMode == true) {
        obtainContext?.call((context) {
          Navigator.of(context).pop(orderEntity);
        });
      } else {
        id = orderEntity.id;
        await post(editDataFuture,
            loadingTip: S.current.loading,
            autoHandler: AutoHandler.Toast, onSuccess: (result) {
          isEdit = false;
          data = transformData(
              getEntityFromResult<CreditNoteDetailEntity>(result), false);
          update();
        });
      }
    }
  }

  void onChangeIssueDate() {
    unFocus();
    obtainContext?.call((context) async {
      date = await showCalendarBottomSheet(context, date);
      update();
    });
  }

  void onChangeIssueTo() async {
    unFocus();
    final result = await Routes.navigateTo(
        RouterGenProviders.businessContactsPage,
        params: {
          'select': issueTo,
        });
    if (result != null) {
      issueTo = result;
      invoiceNumber = null;
      serviceAndProductList.clear();
      update();
    }
  }

  void onChangeInvoiceNumber() async {
    unFocus();
    final result =
        await Routes.navigateTo(RouterGenProviders.invoiceNumberPage, params: {
      'select': invoiceNumber,
      'filterIssueTo': issueTo?.id,
    });
    if (result != null) {
      invoiceNumber = result;
      if (issueTo == null) issueTo = invoiceNumber.contact;
      serviceAndProductList.clear();
      availableItems =
          invoiceNumber.items.map((e) => e.toServiceAndProduct()).toList();
      update();
    }
  }

  @override
  Future get editDataFuture => HttpCreditNoteService.showCreditNote(id);

  @override
  FutureOr<CreditNoteDetailEntity> transformData(
      CreditNoteDetailEntity d, bool isCache) {
    creditNoteNumberController.text = d.number;
    date = DateTimeUtils.toDateTime(d.issuedAt);
    issueTo = d.contact;
    invoiceNumber = InvoiceEntity()
      ..id = d.invoiceId
      ..number = d.invoiceNumber;
    // amount = d.invoiceId
    notesController.text = d.notes;
    serviceAndProductList = d.items != null
        ? d.items.map((e) => e.toServiceAndProduct()).toList()
        : [];

    if (d.status == 'closed') {
      menuList = [
        'See Payment',
      ];
    } else {
      menuList = [
        'Edit',
        'Delete',
        'Make A Refund',
        // 'Keep As Credit',
      ];
    }
    handleDataUpdate(d);
    return super.transformData(d, isCache);
  }

  void onMakeARefund() async {
    await Routes.navigateTo(RouterGenProviders.newCashOutPage, params: {
      'creditNote': data,
      'isSelectMode': true,
    });
    await post(editDataFuture, onSuccess: (result) {
      isEdit = false;
      data = transformData(
          getEntityFromResult<CreditNoteDetailEntity>(result), false);
      update();
    });
  }

  void onKeepAsCredit() {
    obtainContext?.call((context) async {
      final result = await showKeepCreditInfoBottomSheet(context);
      if (result == true) {
        bool isSuccess = false;
        await post(HttpCreditNoteService.keepCreditNote(data.id),
            autoHandler: AutoHandler.Toast,
            loadingTip: S.current.loading, onSuccess: (result) {
          isSuccess = true;
        });
        if (isSuccess) {
          await showKeepAsCreditSuccessTipBottomSheet(context);
          onTry();
        }
      }
    });
  }

  void onDelete() {
    obtainContext?.call((context) async {
      bool isSuccess = await showDeleteCreditNoteInfoBottomSheet(context);
      if (isSuccess == true) {
        isSuccess = false;
        await post(HttpCreditNoteService.deleteCreditNote(data.id),
            loadingTip: 'Loading', onSuccess: (result) {
          isSuccess = true;
        }, autoHandler: AutoHandler.Toast);
        if (isSuccess == true) {
          await showDeleteCreditNoteSuccessBottomSheet(context);
          Navigator.of(context).pop({
            'delete': true,
          });
        }
      }
    });
  }

  @override
  String get type => 'credit_note';

  @override
  TextEditingController get numberCtl => creditNoteNumberController;

  @override
  List<OcrAttachmentEntity> get attachments => data?.attachments;
}
